
#include "CompanyReport.h"

#include "BondContainer.h"
#include "ZippedObjectMap.h"
#include "qbprotocol/include/simple_encoder.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
// #define new DEBUG_NEW
#endif

// TODO:
#ifndef _MSC_VER
#define FIELD_OFFSET(type, field) offsetof(type, field)
#endif  // !_MSC_MSC_VER

//////////////////////////////////////////////////////////////////////
// class CBondCompanyRep

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

/*
        class ReportVec {
        public:
                typedef std::pair<std::string, REPORT> value_type;
                typedef std::vector<value_type> Vector;
                class iterator{
                public:
                        value_type* operator ->();
                        bool operator !=(const iterator& it)const;
                        iterator& operator++();//前缀
                        const iterator operator++(int);//后缀
                };
                class const_iterator{
                public:
                        const value_type* operator ->()const;
                        bool operator !=(const const_iterator& it)const;
                        const_iterator& operator++();
                };

                int size()const;
                void clear(){}
                REPORT& operator[](const std::string& key);
                iterator find(const std::string& key)const;
                iterator begin();
                const_iterator begin()const;
                iterator end();
                const_iterator end()const;
                iterator erase(iterator it);
        };

*/
namespace {

enum kListedMarketType {
  kListedMarketTypeNone,
  kListedMarketTypeCIB,
  kListedMarketTypeSSE,
  kListedMarketTypeSZE,
};
inline bool IsZeroStr(const char* str) {
  return str && str[0] == '0' && str[1] == '\0';
}
inline bool IsEmpty(const char* str) { return (str == NULL || *str == '\0'); }
kListedMarketType GetListedMarketType(const char* listedMarket) {
  if (strcmp(listedMarket, CBondContainer::lmCIB) == 0)
    return kListedMarketTypeCIB;
  else if (strcmp(listedMarket, CBondContainer::lmSSE) == 0)
    return kListedMarketTypeSSE;
  else if (strcmp(listedMarket, CBondContainer::lmSZE) == 0)
    return kListedMarketTypeSZE;
  return kListedMarketTypeNone;
}
kListedMarketType GetListedMarketTypeByCodeDot(const char* dot) {
  if (strcmp(dot, ".IB") == 0) return kListedMarketTypeCIB;
  if (strcmp(dot, ".SH") == 0) return kListedMarketTypeSSE;
  if (strcmp(dot, ".SZ") == 0) return kListedMarketTypeSZE;
  return kListedMarketTypeNone;
}

void CheckReportValid(const REPORT& rpt) {
  // static const char* cause[2] = { "HASDOT ", "INVALID" };
  // const char* dot = strchr(rpt.m_szCode, '.');
  // int dotpos = dot ? (dot - rpt.m_szCode) : (-1);
  // if (dot)
  //{
  //	int select = 0;
  //	kListedMarketType lm = GetListedMarketType(rpt.m_sListedMarket);
  //	kListedMarketType code = GetListedMarketTypeByCodeDot(dot);
  //	if (lm != code || lm == kListedMarketTypeNone || code ==
  //kListedMarketTypeNone)
  //	{
  //		select = 1;
  //	}
  //	int bid = AfxGetBondContainer().GetBondIndex(rpt.m_sBondKey,
  //rpt.m_sListedMarket); 	DebugView(0, 0, 0, "\n[REPORT_CHK] <%s>  bid:%d key:%s
  //lm:%s time:%d create:%d pstatus:%d pkid:%d bid[%s-%s] ask[%s-%s]",
  //		cause[select],bid,
  //		rpt.m_sBondKey, rpt.m_sListedMarket,/* rpt.m_szCode,
  //rpt.m_szShortName,*/ rpt.m_time, rpt.m_create_time, rpt.m_price_status,
  //(int)rpt.m_pkg_id, 		rpt.m_bidinfo.m_price_status,rpt.m_bidinfo.m_sPrice,
  //		rpt.m_askinfo.m_price_status, rpt.m_askinfo.m_sPrice
  //		);
  // }
}

}  // namespace
/*
[内存优化][scofined.qi]
使用vector而不用map,是考虑到以经纪公司id为key,这个个数非常少
用map,每个节点就得多消耗16个字节(三个指针加上2个着色和2个对齐空白字节)
用vector则没有这个开销,另外vector保证数据放在一起,对缓存友好
*/
class ZippedReportMap
    : public ZippedObjectMap<REPORT, ReportEncoder, kObjectMetaIdReport,
                             EncodeBufInfoVector> {};

// 如果要使用之前的结构体,需要做几件事情:
// 1.将头文件的成员注释取消
// 2.构造函数中将m_zip分配注释
// 3.将REPORT_MAP_WRAP宏切换成旧版

// #define  REPORT_MAP_WRAP() MapWrapper<ReportMap>
// map((ReportMap&)m_RepMap.m_map);
#define REPORT_MAP_WRAP() \
  ZippedReportMap::wrapper map((ZippedReportMap&)*m_zip);

CBondCompanyRep::CBondCompanyRep() { m_zip = new ZippedReportMap(); }

CBondCompanyRep::~CBondCompanyRep() {
  Clear();
  if (m_zip) delete m_zip;
}

bool CBondCompanyRep::Clear() {
  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  REPORT_MAP_WRAP();
  map.clear();
  return true;
}

bool CBondCompanyRep::ClearLiquidation(int clrFlag) {
  if (clrFlag == CBondContainer::LIQ_CLR_BESTPRICE_ALL) {
    Clear();
  } else {
    qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
    REPORT_MAP_WRAP();
    for (auto pos = map.begin(); pos != map.end();) {
      if (clrFlag == CBondContainer::LIQ_CLR_BESTPRICE_BROKE &&
          pos->first != "e" &&
          pos->first != "c") {  // 注意：如果只是删除broker的报价，条件需要修改
        pos = map.erase(pos);
      } else if (clrFlag == CBondContainer::LIQ_CLR_BESTPRICE_CFETS &&
                 pos->first == "c") {
        pos = map.erase(pos);
      } else if (clrFlag == CBondContainer::LIQ_CLR_BESTPRICE_EXCHANGE &&
                 pos->first == "e") {
        pos = map.erase(pos);
      } else {
        ++pos;
      }
    }
  }
  return true;
}

bool CBondCompanyRep::InsertCompanyRep(const REPORT& newElement) {
  qb::base::TempTinyString strCompId(newElement.m_company_id);
  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  REPORT_MAP_WRAP();
  map.emplace(strCompId, newElement);
  // m_RepMap.m_map[strCompId] = newElement;
  return true;
}

bool CBondCompanyRep::GetCompanyRepByKey(const std::string& sKey,
                                         REPORT& stRep) {
  qb::base::TempTinyString key(sKey);
  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  REPORT_MAP_WRAP();
  if (map.size() == 0) return false;
  auto itr = map.find(key);
  if (itr != map.end()) {
    stRep = itr->second;
    return true;
  }
  return false;
}

void CBondCompanyRep::ApplyAccess(bool all, const std::string& sKey,
                                  ApplyCallback* callback) {
  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  if (all) {
    REPORT_MAP_WRAP();
    auto it = map.begin();
    for (; it != map.end(); ++it) {
      if (!callback->DoAccess(it->second)) break;
    }
  } else {
    REPORT_MAP_WRAP();
    qb::base::TempTinyString key(sKey);
    auto it = map.find(key);
    if (it != map.end()) callback->DoAccess(it->second);
  }
}
void CBondCompanyRep::ApplyModify(bool all, const std::string& sKey,
                                  ApplyCallback* callback) {
  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  REPORT_MAP_WRAP();
  if (all) {
    auto it = map.begin();
    for (; it != map.end(); ++it) {
      if (!callback->DoModify(it->second)) break;
    }
  } else {
    qb::base::TempTinyString key(sKey);
    auto it = map.find(key);
    if (it != map.end()) callback->DoModify(it->second);
  }
}

int CBondCompanyRep::GetSize() {
  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  REPORT_MAP_WRAP();
  return map.size();
}
const char* CBondCompanyRep::GetName() const { return "CBondCompanyRep"; }
int CBondCompanyRep::GetBytes(int mode) {
  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  int bytes = 1;
  REPORT_MAP_WRAP();
  return map.bytes();
}
bool CBondCompanyRep::GetReport(
    const std::string& sKey, REPORT& stRep,
    int nFlag)  // flag = 0 取最新，1 取最新有效，2 取最新双边
{
  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  REPORT_MAP_WRAP();
  if (map.size() == 0) return false;
  std::string tempKey = sKey;
  if (tempKey.empty()) {
    time_t tLatestTime = 0;
    for (auto itr = map.begin(); itr != map.end(); ++itr) {
      REPORT& report = itr->second;

      if (!IsEmpty(report.m_company_id) &&
          strcmp(report.m_company_id, "e") != 0 &&
          strcmp(report.m_company_id, "c") != 0) {
        time_t tCurTime = max(report.m_time, report.m_create_time);
        bool bBidValid = (report.m_bidinfo.m_price_status[0] != '\0' &&
                          strcmp(report.m_bidinfo.m_price_status, "0") != 0);
        bool bOfrValid = (report.m_askinfo.m_price_status[0] != '\0' &&
                          strcmp(report.m_askinfo.m_price_status, "0") != 0);
        switch (nFlag) {
          case 0:
            if (tCurTime > tLatestTime) {  // 更新
              tempKey = itr->first;
              tLatestTime = tCurTime;
            }
            break;
          case 1:
            if ((bBidValid || bOfrValid) &&
                tCurTime > tLatestTime) {  // 单边有效并更新
              tempKey = itr->first;
              tLatestTime = tCurTime;
            }
            break;
          case 2:
            if (bBidValid && bOfrValid &&
                tCurTime > tLatestTime) {  // 双边有效并更新
              tempKey = itr->first;
              tLatestTime = tCurTime;
            }
            break;
          default:
            // BASSERT(0);
            break;
        }
      }
    }
  }
  if (tempKey.empty()) return false;

  qb::base::TempTinyString key(tempKey);
  auto itr = map.find(key);
  if (itr != map.end()) {
    stRep = itr->second;
    return true;
  }
  return false;
}

bool CBondCompanyRep::GetLatestReport(REPORT& stRep, bool bBuyPool) {
  bool bRes = false;
  memset(&stRep, 0, sizeof(REPORT));
  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  if (GetSize() <= 0) return false;
  time_t tMaxTime = 0;
  REPORT_MAP_WRAP();
  auto itr = map.begin();
  for (; itr != map.end(); itr++) {
    REPORT& rep = itr->second;
    time_t tCurTime = max(rep.m_time, rep.m_create_time);
    if (tMaxTime < tCurTime) {
      if (bBuyPool) {
        if (IsBidPriceValid(rep) || IsOfrPriceValid(rep)) {
          tMaxTime = tCurTime;
          stRep = rep;
          bRes = true;
        }
      } else {
        if (IsBidPriceValid(rep)) {
          tMaxTime = tCurTime;
          stRep = rep;
          bRes = true;
        }
      }
    }
  }
  return bRes;
}

bool CBondCompanyRep::TestBidPrice(const BLHCONDITION& Cond) {
  bool all = IsEmpty(Cond.sCompanyid);
  qb::base::TempTinyString key(Cond.sCompanyid);
  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  REPORT_MAP_WRAP();
  auto it = all ? map.begin() : map.find(key);
  for (; it != map.end(); ++it) {
    const REPORT& rpt = it->second;

    if (IsEmpty(rpt.m_bidinfo.m_yield_price) ||
        strcmp(rpt.m_bidinfo.m_sPrice, "Bid") == 0 ||
        strcmp(rpt.m_bidinfo.m_price_status, "0") ==
            0 /*||strcmp(info.GetEstPrice(),"0")==0*/) {  // 无效价格，或者无效估值
      if (all) continue;
    } else {
      float fBid = atof(
          rpt.m_bidinfo
              .m_yield_price);  // 使用收益率比较，modified by Lance 2020.05.12
      bool bRet = true;
      if (Cond.sBPrice[0] != '\0') {
        if (fBid < atof(Cond.sBPrice) - 1e-6) bRet = false;
      }
      if (Cond.sBPriceEnd[0] != '\0') {
        if (fBid > atof(Cond.sBPriceEnd) + 1e-6) bRet = false;
      }
      if (bRet) return bRet;
    }
    if (!all) break;
  }
  return false;
}

bool CBondCompanyRep::TestOfrPrice(const BLHCONDITION& Cond) {
  bool all = IsEmpty(Cond.sCompanyid);
  qb::base::TempTinyString key(Cond.sCompanyid);
  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  REPORT_MAP_WRAP();
  auto it = all ? map.begin() : map.find(key);
  for (; it != map.end(); ++it) {
    const REPORT& rpt = it->second;

    if (IsEmpty(rpt.m_askinfo.m_yield_price) ||
        strcmp(rpt.m_askinfo.m_sPrice, "Ofr") == 0 ||
        strcmp(rpt.m_askinfo.m_price_status, "0") ==
            0 /*||strcmp(info.GetEstPrice(),"0")==0*/) {  // 无效价格，或者无效估值
      if (all) continue;
    } else {
      float fOfr = atof(
          rpt.m_askinfo
              .m_yield_price);  // 使用收益率比较，modified by Lance 2020.05.12

      bool bRet = true;
      if (Cond.sOPrice[0] != '\0') {
        if (fOfr < atof(Cond.sOPrice) - 1e-6) bRet = false;
      }
      if (Cond.sOPriceEnd[0] != '\0') {
        if (fOfr > atof(Cond.sOPriceEnd) + 1e-6) bRet = false;
      }
      if (bRet) return bRet;
    }
    if (!all) break;
  }

  return false;
}

bool CBondCompanyRep::TestBidOfrPrice(const BLHCONDITION& Cond) {
  bool all = IsEmpty(Cond.sCompanyid);
  qb::base::TempTinyString key(Cond.sCompanyid);
  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  REPORT_MAP_WRAP();
  auto it = all ? map.begin() : map.find(key);
  for (; it != map.end(); ++it) {
    const REPORT& rpt = it->second;

    if (IsEmpty(rpt.m_bidinfo.m_yield_price) ||
        strcmp(rpt.m_bidinfo.m_sPrice, "Bid") == 0 ||
        strcmp(rpt.m_bidinfo.m_price_status, "0") == 0 ||
        IsEmpty(rpt.m_askinfo.m_yield_price) ||
        strcmp(rpt.m_askinfo.m_sPrice, "Ofr") == 0 ||
        strcmp(rpt.m_askinfo.m_price_status, "0") == 0) {  // 单边无效
      if (all) continue;
    } else {
      double fDiff = (atof(rpt.m_bidinfo.m_yield_price) -
                      atof(rpt.m_askinfo.m_yield_price)) *
                     100;  // 使用收益率比较，modified by Lance 2020.05.12
      bool bGood = true;
      if (!IsEmpty(Cond.sBidOfr)) {
        if (fDiff < atof(Cond.sBidOfr) - 1e-6) bGood = false;
      }
      if (!IsEmpty(Cond.sBidOfrEnd)) {
        if (fDiff > atof(Cond.sBidOfrEnd) + 1e-6) bGood = false;
      }
      if (bGood) return true;
    }
    if (!all) break;
  }

  return false;
}

bool CBondCompanyRep::IsBidPriceValid(const REPORT& stRep) {
  if (strcmp(stRep.m_bidinfo.m_price_status, "0") == 0) return false;

  if (atoi(stRep.m_bidinfo.m_rebate) == 1) return true;

  if (!IsEmpty(stRep.m_bidinfo.m_sPrice)) return true;

  return false;
}

bool CBondCompanyRep::IsOfrPriceValid(const REPORT& stRep) {
  if (strcmp(stRep.m_askinfo.m_price_status, "0") == 0) return false;

  if (atoi(stRep.m_askinfo.m_rebate) == 1) return true;

  if (!IsEmpty(stRep.m_askinfo.m_sPrice)) return true;

  return false;
}
typedef ReportEncoder::FieldArray FieldArray;
time_t CBondCompanyRep::GetModifyTime(const std::string& key) {
  // 参照CBondUtil::GetModifyTime
  // 4,5对应于REPORT的第4,5个字段,按照顺序
  // 以下静态断言,用于确保report_t结构体中的每个字段不会被意外修改
  // 尤其是顺序,因为GetField严格依赖每个字段对应的顺序
  static_assert(sizeof(price_t) == 478, "sizeof(price_t) must be 478");
  static_assert(sizeof(indx_price_t) == 40, "sizeof(indx_price_t) must be 40");
  static_assert(sizeof(report_t) == 1122, "sizeof(report_t) must be 1122");

  static_assert(FIELD_OFFSET(REPORT, m_dwVersion) == 0,
                "REPORT.m_dwVersion offset must be 0");
  static_assert(FIELD_OFFSET(REPORT, m_dwMarket) == 4,
                "REPORT.m_dwMarket offset must be 4");
  static_assert(FIELD_OFFSET(REPORT, m_sBondKey) == 8,
                "REPORT.m_sBondKey offset must be 8");
  static_assert(FIELD_OFFSET(REPORT, m_sListedMarket) == 41,
                "REPORT.m_sListedMarket offset must be 41");
  static_assert(FIELD_OFFSET(REPORT, m_time) == 49,
                "REPORT.m_time offset must be 49");
  static_assert(FIELD_OFFSET(REPORT, m_create_time) == 57,
                "REPORT.m_create_time offset must be 57");
  static_assert(FIELD_OFFSET(REPORT, m_bp_status) == 65,
                "REPORT.m_deal_status offset must be 65");
  static_assert(FIELD_OFFSET(REPORT, m_company_id) == 69,
                "REPORT.m_company_id offset must be 69");
  static_assert(FIELD_OFFSET(REPORT, m_price_status) == 102,
                "REPORT.m_price_status offset must be 102");
  static_assert(FIELD_OFFSET(REPORT, m_bidinfo) == 105,
                "REPORT.m_bidinfo offset must be 105");
  static_assert(FIELD_OFFSET(REPORT, m_askinfo) == 583,
                "REPORT.m_askinfo offset must be 583");
  static_assert(FIELD_OFFSET(REPORT, m_indx_info) == 1061,
                "REPORT.m_indx_info offset must be 1061");
  static_assert(FIELD_OFFSET(REPORT, m_price_sel) == 1101,
                "REPORT.m_price_sel offset must be 1101");
  static_assert(FIELD_OFFSET(REPORT, m_tradePrice) == 1102,
                "REPORT.m_tradePrice offset must be 1102");
  static_assert(FIELD_OFFSET(REPORT, m_pkg_id) == 1114,
                "REPORT.m_pkg_id offset must be 1114");

  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  if (key.empty()) {
    time_t tLatestTime = 0;
    EncodeBufInfo infos[16];
    int ncount = m_zip->getall(infos, _countof(infos));
    for (int i = 0; i < ncount; i++) {
      FieldArray* fa = (FieldArray*)infos[i].buf;
      if (fa == nullptr) continue;
      const char* companyId =
          (const char*)fa->GetField((int)kReportField::CompanyId);
      if (!IsEmpty(companyId) && strcmp(companyId, "e") != 0 &&
          strcmp(companyId, "c") != 0) {
        time_t t1 = *((const time_t*)fa->GetField((int)kReportField::Time));
        time_t t2 =
            *((const time_t*)fa->GetField((int)kReportField::CreateTime));
        time_t tCurTime = max(t1, t2);
        if (tCurTime > tLatestTime) tLatestTime = tCurTime;
      }
    }
    return tLatestTime;
  } else {
    qb::base::TempTinyString tempKey(key);
    EncodeBufInfo info = m_zip->find(tempKey);
    if (info.buf) {
      FieldArray* fa = (FieldArray*)info.buf;
      time_t t1 = *((const time_t*)fa->GetField((int)kReportField::Time));
      time_t t2 = *((const time_t*)fa->GetField((int)kReportField::CreateTime));
      return max(t1, t2);
    }
  }
  return 0;
}
double CBondCompanyRep::GetBuyNetPrice(const std::string& key) {
  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  double idval = MIN_VAL;
  qb::base::TempTinyString tempKey(key);
  EncodeBufInfo info = m_zip->find(tempKey);
  FieldArray* fa = (FieldArray*)info.buf;
  if (fa)
    idval = atof((const char*)fa->GetField((int)kReportField::Bid_clean_price));
  return idval;
}
const void* CBondCompanyRep::GetReportField(const char* key, int index) {
  qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
  static const char dft_value[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  qb::base::TempTinyString tempKey(key);
  EncodeBufInfo info = m_zip->find(tempKey);
  if (info.buf && index >= 0 && index < (int)kReportField::Count) {
    FieldArray* fa = (FieldArray*)info.buf;
    return fa->GetField(index);
  }
  return dft_value;
}

bool CBondCompanyRep::IsHasPrice(const char* szKey, int flag) {
  EncodeBufInfo infos[16];
  int ncount = 0;
  {
    qb::base::ScopedLock<qb::base::Spinlock> l(m_lock);
    if (szKey == nullptr || IsEmpty(szKey))
      ncount = m_zip->getall(infos, _countof(infos));
    else {
      qb::base::TempTinyString tempKey(szKey);
      infos[0] = m_zip->find(tempKey);
      if (infos[0].buf != nullptr) ncount = 1;
    }
  }

  for (int i = 0; i < ncount; i++) {
    FieldArray* fa = (FieldArray*)infos[i].buf;
    const char* bid_price_status =
        (const char*)fa->GetField((int)kReportField::Bid_price_status);
    const char* ask_price_status =
        (const char*)fa->GetField((int)kReportField::Ask_price_status);
    bool bidStatus = !IsZeroStr(bid_price_status);
    bool ofrStatus = !IsZeroStr(ask_price_status);
    if (!bidStatus && !ofrStatus) continue;
    const char* bid_rebate =
        (const char*)fa->GetField((int)kReportField::Bid_rebate);
    const char* ask_rebate =
        (const char*)fa->GetField((int)kReportField::Ask_rebate);
    switch (flag) {
      case CBondContainer::BidValid:
        if (bidStatus && atoi(bid_rebate) == 1) return true;
        break;
      case CBondContainer::OfrValid:
        if (ofrStatus && atoi(ask_rebate) == 1) return true;
        break;
      case CBondContainer::BothValid:
        if ((bidStatus && atoi(bid_rebate) == 1) &&
            (ofrStatus && atoi(ask_rebate) == 1))
          return true;
        break;
      case CBondContainer::SingleValid:
      default:
        if ((bidStatus && atoi(bid_rebate) == 1) ||
            (ofrStatus && atoi(ask_rebate) == 1))
          return true;
        break;
    }

    const char* bid_price =
        (const char*)fa->GetField((int)kReportField::Bid_sPrice);
    const char* ask_price =
        (const char*)fa->GetField((int)kReportField::Ask_sPrice);
    switch (flag) {
      case CBondContainer::BidValid:
        if (bidStatus && !IsEmpty(bid_price)) return true;
        break;
      case CBondContainer::OfrValid:
        if (ofrStatus && !IsEmpty(ask_price)) return true;
        break;
      case CBondContainer::BothValid:
        if ((bidStatus && !IsEmpty(bid_price)) &&
            (ofrStatus && !IsEmpty(ask_price)))
          return true;
        break;
      case CBondContainer::SingleValid:
      default:
        if (((bidStatus && !IsEmpty(bid_price)) ||
             (ofrStatus && !IsEmpty(ask_price))))
          return true;
        break;
    }
  }
  return false;
}

// 5.6w
/*TODO
static_assert(sizeof(PRICE) == 466, "");
static_assert(sizeof(REPORT) == 1098, "");
static_assert(sizeof(std::string) == 24, "");

static_assert(sizeof(CCompanyRepMap::ReportMap::_Node) == 1100 + 24 + 16, "");
static_assert(sizeof(CCompanyRepMap) ==8, "");
static_assert(sizeof(CBondCompanyRep) == 12, "");
//static_assert(sizeof(ZippedReportMap) == 12, "");
*/
